<repo_name>OnTheGoSystems/wpml-link-manager<file_sep>/tests/tests/classes/test-wpml-link-manager-helper.php
<?php

class Test_WPML_Link_Manager_Helper extends WPML_UnitTestCase {

	private $lm_helper;

	public function setUp() {
		parent::setUp();
		$package_type = 'Link Manager';
		$this->lm_helper = new WPML_Link_Manager_Helper( $package_type );
	}

	public function test_get_package_type() {
		$package_type = 'Link Manager';
		$this->lm_helper = new WPML_Link_Manager_Helper( $package_type );

		$this->assertEquals( $this->lm_helper->get_package_type(), $package_type);

	}

	public function test_get_package() {
		$link = new stdClass();
		$link->link_id   = 3;
		$link->link_name = 'test link';
		$link->link_url  = 'http://example.com';
		$package = $this->lm_helper->get_package( $link );
		$this->assertEquals( 'link', substr( $package['kind'], -4, 4 ) );

		$cat = new stdClass();
		$cat->term_id = 6;
		$cat->name    = 'test cat';
		$package = $this->lm_helper->get_package( $cat, 'category' );
		$this->assertEquals( 'category', substr( $package['kind'], -8, 8 ) );

		$package = $this->lm_helper->get_package( 19 );
		$this->assertEquals( 'link', substr( $package['kind'], -4, 4 ) );

		$package = $this->lm_helper->get_package( 19, 'category' );
		$this->assertEquals( 'category', substr( $package['kind'], -8, 8 ) );
	}

	public function test_get_link_string_name() {
		$name = 'name';
		$link = new stdClass();
		$link->link_id = 12;

		$str_name = $this->lm_helper->get_link_string_name( $name, $link );
		$this->assertEquals( 'link-' . $link->link_id . '-' . $name, $str_name );
	}

	public function test_get_category_string_name() {
		$name = 'name';
		$cat = new stdClass();
		$cat->term_id = 15;

		$str_name = $this->lm_helper->get_category_string_name( $name, $cat );
		$this->assertEquals( 'link-category-' . $cat->term_id . '-' . $name, $str_name );
	}
}<file_sep>/tests/bootstrap.php
<?php
if ( ! defined( 'WPML_CORE_PATH' ) ) {
	define( 'WPML_CORE_PATH', dirname( __FILE__ ) . '/../../sitepress-multilingual-cms' );
}
if ( ! defined( 'WPML_CORE_ST_PATH' ) ) {
	define( 'WPML_CORE_ST_PATH', dirname( __FILE__ ) . '/../../wpml-string-translation' );
}
if ( ! defined( 'WPML_CORE_TM_PATH' ) ) {
	define( 'WPML_CORE_TM_PATH', dirname( __FILE__ ) . '/../../wpml-translation-management' );
}
define( 'WPML_ST_TEST_DIR', dirname( __FILE__ ) . '/../../wpml-string-translation/tests' );
$_tests_dir = isset( $_ENV['WP_TEST_DIR'] ) ? $_ENV['WP_TEST_DIR'] : 'wordpress-tests-lib';
require_once $_tests_dir . '/includes/functions.php';

function _manually_load_plugin() {
	require WPML_CORE_PATH . '/tests/util/functions.php';
	require WPML_CORE_PATH . '/sitepress.php';
	require WPML_CORE_ST_PATH . '/plugin.php';
	require WPML_CORE_TM_PATH . '/plugin.php';
	require dirname( __FILE__ ) . '/../plugin.php';
}

tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' );

function _make_wpml_setup_complete() {
	icl_set_setting( 'setup_complete', 1, true );
}
tests_add_filter( 'wpml_loaded', '_make_wpml_setup_complete' );

// Make sure Link Manager plugin is on
function _enable_link_manager() {
	return true;
}
tests_add_filter( 'pre_option_link_manager_enabled', '_enable_link_manager', 1000 );

require $_tests_dir . '/includes/bootstrap.php';
require WPML_CORE_PATH . '/tests/util/wpml-unittestcase.class.php';
//require WPML_CORE_ST_PATH . '/tests/util/wpml-st-unittestcase.class.php';<file_sep>/readme.md
# WPML Link Manager
> Makes the plugin Link Manager compatible with WPML translating features

## Minimum requirements
* **Sitepress Multilingual CMS** installed and activated
* **WPML Translation management** installed and activated
* **WPML String translation** installed and activated
* **Link Manager plugin** installed and activated (available in the [WordPress official repository](https://wordpress.org/plugins/link-manager/))

## Installation
1. Download **WPML Link Manager** folder and paste it in `wp-content/plugins`
2. In **Plugins** admin page, activate **WPML Link Manager**

## How it works?
Basically, all link information such as link title, link description and category title are translated as strings.
So all the links (already existing or added) are considered in the default language of the site.
The link related strings are translatable in **WPML > String translation**

1. Create (or edit) a link in **Links** admin page.
2. Go to **WPML > String translation**
3. Select the domain related to this link (`link-manager-link-{link_id}`)
4. Translate the title and description in secondary languages

The same process applies for link categories:

1. Create (or edit) a link category in **Links** admin page.
2. Go to **WPML > String translation**
3. Select the domain related to this link category (`link-manager-category-{category_id}`)
4. Translate the title and description in secondary languages

<file_sep>/tests/tests/classes/test-wpml-link-manager.php
<?php

class Test_WPML_Link_Manager extends WPML_UnitTestCase {

	/**
	 * @var WPML_Link_Manager
	 */
	private $lm;
	/**
	 * @var WPML_Link_Manager_Helper
	 */
	private $lm_helper;

    public function test_add_or_edit_link_action() {
        $this->instantiate_link_manager( 'link.php' );

        $args = array(
                "link_url"		=> 'http://test.com',
                "link_name"		=> 'The link name',
                "link_description"	=> 'The link description',
        );
        $link_id = wp_insert_link( $args );

        // check if name & description strings are registered
        $link = get_bookmark( $link_id );
        $context = $this->get_link_string_context( $link_id );
        $name_name = $this->lm_helper->get_link_string_name( 'name', $link );
        $name_desc = $this->lm_helper->get_link_string_name( 'description', $link );

        $link_has_strings = false;
        if ( icl_get_string_id( $link->link_name, $context, $name_name ) && icl_get_string_id( $link->link_description, $context, $name_desc ) ) {
            $link_has_strings = true;
        }

        $this->assertTrue( $link_has_strings );
    }

    public function test_get_bookmarks_filter() {
        global $sitepress, $wpdb, $WPML_String_Translation;
        $orig_lang    = 'en';
        $sec_lang     = 'fr';
        $name_base    = 'The link ';
        $desc_base    = 'The link description ';

        $wpml_installation = new WPML_Installation( $wpdb, $sitepress );
        $wpml_installation->set_active_languages( array( $orig_lang, $sec_lang) );
        $WPML_String_Translation->init_active_languages();

        $this->instantiate_link_manager( 'link.php' );

        $sitepress->switch_lang( $orig_lang );

        $links = array();
        for ($i=0; $i < 3; $i++) {
            $args = array(
                    "link_url" => 'http://test' . $i,
                    "link_name" => $name_base . $i,
                    "link_description" => $desc_base . $i,
            );

            $link_id = wp_insert_link( $args );
            $links[ $i ] = get_bookmark( $link_id );

            $context = $this->get_link_string_context( $link_id );

            $name_st_id = icl_get_string_id( $links[ $i ]->link_name, $context, $this->lm_helper->get_link_string_name( 'name', $links[ $i ] ) );
            $desc_st_id = icl_get_string_id( $links[ $i ]->link_description, $context, $this->lm_helper->get_link_string_name( 'description', $links[ $i ] ) );

            icl_add_string_translation( $name_st_id, $sec_lang, $name_base . $i . $sec_lang, ICL_TM_COMPLETE );
            icl_add_string_translation( $desc_st_id, $sec_lang, $desc_base . $i . $sec_lang, ICL_TM_COMPLETE );
        }

        $sitepress->switch_lang( $sec_lang );
        $this->instantiate_link_manager( 'front' ); // Switch to front end

        $translated_links = $this->lm->get_bookmarks_filter( $links );

        foreach ( $translated_links as $i => $link ) {
            $this->assertEquals( $name_base . $i . $sec_lang, $link->link_name );
            $this->assertEquals( $desc_base . $i . $sec_lang, $link->link_description );
        }

    }

    public function test_deleted_link_action() {
        $this->instantiate_link_manager( 'link.php' );

        $args = array(
                "link_url"		    => 'http://test.com',
                "link_name"		    => 'The link name',
                "link_description"	=> 'The link description',
        );

        $link_id = wp_insert_link( $args );
        $link    = get_bookmark( $link_id );

        $package = $this->lm_helper->get_package( $link, 'link' );

        $this->assertTrue( $this->package_exist_in_DB( $package ) );

        $this->lm->deleted_link_action( $link_id );

        $this->assertFalse( $this->package_exist_in_DB( $package ) );

    }

    public function test_plugin_activation_action() {
        wpml_link_manager_activation();

        $option = get_option( 'wpml-package-translation-refresh-required' );

        $this->assertTrue( $option );
    }

	public function test_get_terms_filter() {
        global $sitepress, $wpdb, $WPML_String_Translation;
        $orig_lang    = 'en';
        $sec_lang     = 'fr';
        $name_base    = 'The cat ';
        $desc_base    = 'The cat description ';
        $taxonomy     = 'link_category';

        $wpml_installation = new WPML_Installation( $wpdb, $sitepress );
        $wpml_installation->set_active_languages( array( $orig_lang, $sec_lang) );
        $WPML_String_Translation->init_active_languages();

        $this->instantiate_link_manager( 'edit-tags.php' );

        $sitepress->switch_lang( $orig_lang );

        $cats = $cat_ids = array();
        for ($i=0; $i < 3; $i++) {
            $term       = wp_insert_term( $name_base . $i, $taxonomy, array( 'description' => $desc_base . $i ) );
            $cats[ $i ] = get_term( $term['term_id'], $taxonomy );
            $cat_ids[]  = $term['term_id'];

            $context = $this->get_category_string_context( $cats[ $i ] );

            $name_st_id = icl_get_string_id( $cats[ $i ]->name, $context, $this->lm_helper->get_category_string_name( 'name', $cats[ $i ] ) );
            $desc_st_id = icl_get_string_id( $cats[ $i ]->description, $context, $this->lm_helper->get_category_string_name( 'description', $cats[ $i ] ) );

            icl_add_string_translation( $name_st_id, $sec_lang, $name_base . $i . $sec_lang, ICL_TM_COMPLETE );
            icl_add_string_translation( $desc_st_id, $sec_lang, $desc_base . $i . $sec_lang, ICL_TM_COMPLETE );
        }

        $sitepress->switch_lang( $sec_lang );
        $this->instantiate_link_manager( 'front' );

		/** @var WPML_String_Translation $WPML_String_Translation */
		global $WPML_String_Translation;
        $WPML_String_Translation->clear_string_filter( 'fr' );

        $translated_cats = $this->lm->get_terms_filter( $cats, array( $taxonomy ) );

        foreach ( $translated_cats as $i => $cat ) {
            $this->assertEquals( $name_base . $i . $sec_lang, $cat->name );
            $this->assertEquals( $desc_base . $i . $sec_lang, $cat->description );
        }
    }

    public function test_created_or_edited_link_category_action() {
        $this->instantiate_link_manager( 'edit-tags.php' );

        $cat_name = "My cat";
        $taxonomy = 'link_category';
        $args = array(
                'description' => "My cat description",
        );

        $term = wp_insert_term( $cat_name, $taxonomy, $args );
        $cat = get_term( $term['term_id'], $taxonomy );

        // check if name & description strings are registered
        $context = $this->get_category_string_context( $cat );
        $name_name = $this->lm_helper->get_category_string_name( 'name', $cat );
        $name_desc = $this->lm_helper->get_category_string_name( 'description', $cat );

        $cat_has_strings = false;
        if ( icl_get_string_id( $cat->name, $context, $name_name ) && icl_get_string_id( $cat->description, $context, $name_desc ) ) {
            $cat_has_strings = true;
        }

        $this->assertTrue( $cat_has_strings );
    }

    public function test_delete_term_action() {
        $this->instantiate_link_manager( 'edit-tags.php' );

        $cat_name = "My cat";
        $taxonomy = 'link_category';
        $args = array(
            'description' => "My cat description",
        );

        $term = wp_insert_term( $cat_name, $taxonomy, $args );
        $cat = get_term( $term['term_id'], $taxonomy );

        $package = $this->lm_helper->get_package( $cat, 'category' );

        $this->assertTrue( $this->package_exist_in_DB( $package ) );

        $this->lm->delete_term_action( $cat->term_id, null, $taxonomy );

        $this->assertFalse( $this->package_exist_in_DB( $package ) );
    }

    /**
     * @param string $pagenow
     */
    private function instantiate_link_manager( $pagenow = 'front' ) {

        set_current_screen( $pagenow );

        $this->reload_package_translation();

        $package_type    = 'Link Manager';
        $this->lm_helper = new WPML_Link_Manager_Helper( $package_type );
        $this->lm        = new WPML_Link_Manager( $pagenow, $this->lm_helper );

        // Fire again plugins_loaded action
        $this->lm->plugins_loaded_action();
    }

    private function reload_package_translation() {
        global $WPML_package_translation;
        $WPML_package_translation = new WPML_Package_Translation();
        $WPML_package_translation->loaded();
    }

    /**
     * @param int $link_id
     *
     * @return string
     */
    private function get_link_string_context( $link_id ) {
        $package_helper = new WPML_Package_Helper();
        return $package_helper->get_string_context_from_package( $this->lm_helper->get_package( $link_id, 'link' ) );
    }

    /**
     * @param object $cat
     *
     * @return string
     */
    private function get_category_string_context( $cat ) {
        $package_helper = new WPML_Package_Helper();
        return $package_helper->get_string_context_from_package( $this->lm_helper->get_package( $cat->term_id, 'category' ) );
    }

    /**
     * @param array $package
     *
     * @return bool
     */
    private function package_exist_in_DB( $package ) {
        global $wpdb;

        $query         = "SELECT ID FROM {$wpdb->prefix}icl_string_packages WHERE kind=%s AND name=%s";
        $query_prepare = $wpdb->prepare( $query, $package['kind'], $package['name'] );
        $ret           = $wpdb->get_var( $query_prepare );

        return (bool) $ret;
    }
}<file_sep>/classes/class-wpml-link-manager.php
<?php

Class WPML_Link_Manager {

	private $pagenow;
	private $helper;

	/**
	 * @param string $pagenow
	 * @param object $helper
	 */
	public function __construct( &$pagenow, &$helper ) {
		$this->pagenow = &$pagenow;
		$this->helper  = &$helper;
		add_action( 'plugins_loaded', array( $this, 'plugins_loaded_action' ) );
	}

	public function plugins_loaded_action() {
		if ( !apply_filters( 'pre_option_link_manager_enabled', false ) ) {
			return;
		}

		$this->hooks();
		$this->maybe_add_package_language_switcher();
	}

	public function hooks() {
		add_action( 'add_link',                      array( $this, 'add_or_edit_link_action' ) );
		add_action( 'edit_link',                     array( $this, 'add_or_edit_link_action' ) );
		add_filter( 'get_bookmarks',                 array( $this, 'get_bookmarks_filter' ) );
		add_action( 'deleted_link',                  array( $this, 'deleted_link_action' ) );
		add_action( 'add_meta_boxes',                array( $this, 'add_meta_boxes_action' ) );
		add_action( 'wpml_register_string_packages', array( $this, 'wpml_register_string_packages_action' ) );
		add_filter( 'get_terms',                     array( $this, 'get_terms_filter' ), 10, 2 );
		add_action( 'created_link_category',         array( $this, 'created_or_edited_link_category_action' ) );
		add_action( 'edited_link_category',          array( $this, 'created_or_edited_link_category_action' ) );
		add_action( 'deleted_link',                  array( $this, 'deleted_link_action' ), 10, 4 );
		add_action( 'delete_term',                   array( $this, 'delete_term_action' ), 10, 3 );
	}

	public function maybe_add_package_language_switcher() {
		if ( $this->pagenow === 'link.php'
			&& isset( $_GET['action'], $_GET['link_id'] )
			&& $_GET['action'] === 'edit'
		) {
				$link_id = filter_input(INPUT_GET, 'link_id');
				$package = $this->helper->get_package($link_id);
				do_action('wpml_show_package_language_admin_bar', $package);
		} else if ( $this->pagenow === 'edit-tags.php'
					&& isset( $_GET['taxonomy'], $_GET['tag_ID'] )
					&& $_GET['taxonomy'] === 'link_category'
		) {
				$tag_id = filter_input( INPUT_GET, 'tag_ID' );
				$package = $this->helper->get_package( $tag_id, 'category' );
				do_action( 'wpml_show_package_language_admin_bar', $package );
		}
	}

	/**
	 * @param int $link_id
	 */
	public function add_or_edit_link_action( $link_id ) {
		$this->add_strings_package( $link_id );
	}

	/**
	 * @param int $link_id
	 */
	private function add_strings_package( $link_id ) {
		$link = get_bookmark( $link_id );

		$package = $this->helper->get_package( $link );
		$name_string_name = $this->helper->get_link_string_name( 'name', $link );
		$description_string_name = $this->helper->get_link_string_name( 'description', $link );

		do_action( 'wpml_register_string', $link->link_name, $name_string_name, $package, 'Link title', 'LINE');
		do_action( 'wpml_register_string', $link->link_description, $description_string_name, $package, 'Link description', 'AREA');
	}

	/**
	 * @param array $links objects from get_bookmark()
	 *
	 * @return array
	 */
	public function get_bookmarks_filter( $links ) {
		if ( !is_admin() ) {
			foreach ( $links as &$link ) {
				$package = $this->helper->get_package($link);
				$name_string_name = $this->helper->get_link_string_name('name', $link);
				$description_string_name = $this->helper->get_link_string_name('description', $link);

				$link->link_name = apply_filters('wpml_translate_string', $link->link_name, $name_string_name, $package);
				$link->link_description = apply_filters('wpml_translate_string', $link->link_description, $description_string_name, $package);
			}
		}
		return $links;
	}

	/**
	 * @param int $link_id
	 */
	public function deleted_link_action( $link_id ) {
		$this->delete_strings_package( $link_id, 'link' );
	}

	/**
	 * @param int    $link_id
	 * @param string $subtype
	 */
	private function delete_strings_package( $link_id, $subtype ) {
		do_action( 'wpml_delete_package_action', $link_id, $this->helper->get_package_type() . ' - ' . $subtype );
	}

	public function add_meta_boxes_action() {
		add_meta_box( 'link-translation', __( 'Link translation', 'wpml-link-manager' ), array( $this, 'render_package_language_ui' ), 'link', 'side', 'default' );
	}

	public function render_package_language_ui() {
		$link_id = isset( $_GET['link_id'] ) ? $_GET['link_id'] : false;

		$package = $this->helper->get_package( $link_id );

		do_action( 'wpml_show_package_language_ui', $package );
	}

	public function wpml_register_string_packages_action() {

		$links = get_bookmarks();

		if ( $links ) {
			foreach ( $links as $link ) {
				$this->add_strings_package( $link->link_id );
			}
		}

		$link_categories = get_terms( 'link_category' );

		if ( $link_categories ) {
			foreach ( $link_categories as $link_category ) {
				$this->created_or_edited_link_category_action( $link_category->term_id );
			}
		}

		ICL_AdminNotifier::add_instant_message(
			__( 'Previous existing links are now available for translation', 'wpml-link-manager' ),
			'update'
		);
	}

	/**
	 * @param array $categories
	 * @param array $taxonomies
	 *
	 * @return array $cat_name Category name
	 */
	public function get_terms_filter( $categories, $taxonomies ) {

		if ( !is_admin() && in_array( 'link_category', $taxonomies ) ) {
			foreach ( $categories as &$category ) {
				$package = $this->helper->get_package( $category, 'category' );
				$name_string_name = $this->helper->get_category_string_name( 'name', $category );
				$description_string_name = $this->helper->get_category_string_name( 'description', $category );

				$category->name = apply_filters( 'wpml_translate_string', $category->name, $name_string_name, $package );
				$category->description = apply_filters( 'wpml_translate_string', $category->description, $description_string_name, $package );
			}
		}
		return $categories;
	}

	/**
	 * @param int $term_id Term ID.
	 */
	public function created_or_edited_link_category_action( $term_id ) {
		$link_category = get_term( $term_id, 'link_category' );

		if ( $link_category ) {
			$package = $this->helper->get_package( $link_category, 'category' );
			$name_string_name = $this->helper->get_category_string_name( 'name', $link_category );
			$description_string_name = $this->helper->get_category_string_name( 'description', $link_category );

			do_action( 'wpml_register_string', $link_category->name, $name_string_name, $package, 'Link Category title', 'LINE');
			do_action( 'wpml_register_string', $link_category->description, $description_string_name, $package, 'Link Category description', 'AREA');
		}
	}

	/**
	 * @param int     $term         Term ID.
	 * @param int     $tt_id        Term taxonomy ID.
	 * @param string  $taxonomy     Taxonomy slug.
	 */
	public function delete_term_action( $term, $tt_id, $taxonomy ) {
		if ( 'link_category' === $taxonomy ) {
			$this->delete_strings_package( $term, 'category' );
		}
	}

}<file_sep>/plugin.php
<?php
/* Plugin Name: WPML Link Manager
 * Description: Makes Link Manager (in the core before WP 3.5) compatible with WPML > 3.2
 * Author: OnTheGoSystems
 * Author URL: http://wpml.org/
 * Version: 0.1-dev
 */

define( 'WPML_LINK_MANAGER_PATH', dirname( __FILE__ ) );

function wpml_link_manager_load_plugin() {
    global $pagenow;

    $wpml_auto_loader_instance = WPML_Auto_Loader::get_instance();
    $wpml_auto_loader_instance->register( WPML_LINK_MANAGER_PATH . '/' );

    $package_type = 'Link Manager';
    $helper = new WPML_Link_Manager_Helper( $package_type );
    new WPML_Link_Manager( $pagenow, $helper );
}
add_action( 'wpml_loaded', 'wpml_link_manager_load_plugin' );

function wpml_link_manager_maybe_remove_admin_ls() {
    global $pagenow;
    if ( $pagenow === 'link.php'
        || $pagenow === 'link-manager.php'
        || $pagenow === 'link-add.php'
        || ( $pagenow === 'edit-tags.php' && isset( $_GET['taxonomy'] ) && $_GET['taxonomy'] === 'link_category' ) ) {
            add_filter( 'wpml_show_admin_language_switcher', '__return_false' );
    }
}
add_action( 'wpml_before_init', 'wpml_link_manager_maybe_remove_admin_ls' );

function wpml_link_manager_activation() {
    update_option( 'wpml-package-translation-refresh-required', true );
}
register_activation_hook( __FILE__, 'wpml_link_manager_activation' );<file_sep>/classes/class-wpml-link-manager-helper.php
<?php

Class WPML_Link_Manager_Helper {

    private $package_type;

    /**
     * @param string $package_type
     */
    public function __construct( $package_type ) {
        $this->package_type = $package_type;
    }

    public function get_package_type() {
        return $this->package_type;
    }

    /**
     * @param int|object $link_or_cat
     * @param string     $subtype
     *
     * @return array $package
     */
    public function get_package( $link_or_cat, $subtype = 'link' ) {
        $package = null;
        $package_subtype = $this->package_type . ' - ' . $subtype;

        if ( is_object( $link_or_cat ) ) {
            if ( 'link' === $subtype ) {
                $package = array(
                    'kind'      => $package_subtype,
                    'name'      => $link_or_cat->link_id,
                    'title'     => $link_or_cat->link_name,
                    'edit_link' => admin_url( 'link.php?action=edit&link_id=' . $link_or_cat->link_id ),
                    'view_link' => $link_or_cat->link_url,
                );
            } elseif ( 'category' === $subtype ) {
                $package = array(
                    'kind' => $package_subtype,
                    'name' => $link_or_cat->term_id,
                    'title' => $link_or_cat->name,
                    'edit_link' => admin_url('edit-tags.php?action=edit&taxonomy=link_category&tag_ID=' . $link_or_cat->term_id),
                );
            }
        } else {
            $package = array(
                'kind' 		=> $package_subtype,
                'name' 		=> $link_or_cat,
            );
        }

        return $package;
    }

    /**
     * @param string $name
     * @param object $link
     *
     * @return string formatted
     */
    public function get_link_string_name( $name, $link ) {
        return 'link-' . $link->link_id . '-' . $name;
    }

    /**
     * @param string $name
     * @param object $category
     *
     * @return string formatted
     */
    public function get_category_string_name( $name, $category ) {
        return 'link-category-' . $category->term_id . '-' . $name;
    }

}