<?php
if ( ! defined( 'ABSPATH' ) ) exit();
/**
* I think this file is not used, and probably should be removed.
*
* @package lingotek-translation
*/
// phpcs:disable
if ( ! class_exists( 'WP_List_Table' ) ) {
// since WP 3.1
require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
}
/**
*Requires and evaluates the Lingotek_FormatConverter.php before continuing. If it is not
*found then a fatal error is thrown
*
*@author Unkown
*@link http://php.net/manual/en/function.include.php
*@see FormatConverter.php
*/
require_once 'FormatConverter.php';
settings_errors();
/**
* $client is an API call for the client logged in. This gives the end-user the ability
* to manipulate their documents
*
* @uses lingotek-translation/include/api.php/Lingotek_API
* @deprecated since 24 May 2016 This was making an extra API call and making load
* time very slow.
*/
//$client = new Lingotek_API();
//$docs = $client->get_documents(array('limit'=>5000));
//$communities = $client->get_communities();
/**
* This class is used to prepare the import table that is displayed when users go
* to the import tab.
*
* @author Unkown
*/
class Lingotek_Import_Table extends WP_List_Table {
var $client = null;
var $doc_data = array();
var $projects = array();
var $import_status = null;
var $supported_extentions = array( 'json', 'xml' );
var $document_count = 0;
/**
* Used to mark the number of successful imports on a bulk import
*
* @author TJ Murphy
*/
var $import_success_count = 0;
/**
* Used to mark the number of failed imports on a bulk import
*
* @author TJ Murphy
*/
var $import_failure_count = 0;
/**
* Used to gather the doc ids for documents that did not import as expected
*
* @author TJ Murphy
*/
var $unsuccessful_imports = array();
/**
* Constructor
*
* @author Unkown and TJ Murphy
* @uses lingotek-translation/include/api.php/Lingotek_API
* @see Lingotek_Import_Table::get_docs()
* @see Lingotek_Import_Table::format_docs()
*/
function __construct() {
$this->client = new Lingotek_API();
$this->projects = $this->get_projects( $this->client->get_communities() );
$this->document_count = $this->client->get_document_count();
/**
*Sets $import_success_count to ZERO
*
*@author TJ Murphy
*/
$this->import_success_count = 0;
/**
*Sets $import_failure_count to ZERO
*
*@author TJ Murphy
*/
$this->import_failure_count = 0;
/**
*Sets $unsuccessful_imports to a blank array
*
*@author TJ Murphy
*/
$this->unsuccessful_imports = array();
/**
*This will get ALL docs for the client
*
*@author TJ Murphy
*@see Lingotek_Import_Table::get_docs()
*@see Lingotek_Import_Table::format_docs()
*/
$docs = $this->get_docs( $this->client, $this->document_count );
$this->doc_data = $this->format_docs( $docs );
global $status, $page;
parent::__construct(
array(
'singular' => 'post',
'plural' => 'posts',
'ajax' => false,
)
);
}
/**
* This function is to access the count of successful imports. It is used for both
* bulk and single imports. This is used for a few checks and a few messages that
* get displayed to the end-user after imports occur
*
* @author TJ Murphy
* @uses Lingotek_Import_Table::$import_success_count
* @return void
*/
function add_one_import_success_count() {
$this->import_success_count++;
}
/**
* This function is to add the doc ids of the failed imports to an array so that
* they can be displayed to the end-user. This just gives them more information
* about the errors they may encounter. It also handles the counts for failed imports.
*
* @author TJ Murphy
* @param string $doc_id
* @return void
*/
function add_doc_id_to_unsuccessful_imports( $doc_id ) {
array_push( $this->unsuccessful_imports, $doc_id );
$this->import_failure_count++;
}
/**
* This function is to list the captured doc ids in a string separated by commas
* so it can be displayed for the end-user in a message.
*
* @author TJ Murphy
* @uses Lingotek_Import_Table::$unsuccessful_imports
* @return string $unsuccessful_imports_string this creates an HTML string that
* creates an unordered list of doc ids that failed to import
*/
function to_string_unsuccessful_imports() {
$unsuccessful_imports_string = '<div><ul>';
foreach ( $this->unsuccessful_imports as $doc_id ) {
$unsuccessful_imports_string = $unsuccessful_imports_string . '<li>' . (string) $doc_id . '</li>';
}
$unsuccessful_imports_string = $unsuccessful_imports_string . '</ul></div>';
return $unsuccessful_imports_string;
}
/**
* Calls the API to get all the projects from the TMS and show them for the end-user
*
* @author Unkown
* @uses lingotek-translation/include/api.php/Lingotek_API::get_projects()
* @param $communitites
* @return array $new_projects an array of projects with key/value of (project id, project title)
*/
function get_projects( $communities ) {
$new_projects = array();
foreach ( $communities->entities as $community ) {
$projects = $this->client->get_projects( $community->properties->id )->entities;
foreach ( $projects as $project ) {
$new_projects[ $project->properties->id ] = $project->properties->title;
}
}
return $new_projects;
}
/**
* Get a list of projects or use id to get the corresponding project
* extract doc data and insert into correct structure for rendering
*
* @author Unkown
* @uses Lingotek_Import_Table::get_option()
* @param object $docs list of files that need to be properly formatted to show
* in the table
* @return array $result an array of properly formatted objects to be put into
* the table
*/
function format_docs( $docs ) {
$result = array();
$count = 1;
$resources = get_option( 'lingotek_community_resources' );
$projectInfoArray = $resources['projects'];
foreach ( $docs as $doc ) {
/**
*Convert date from unix time and properly format it
*
*@author Unkown
*/
$unix_upload_time = $doc->properties->upload_date / 1000;
$upload_date_str = gmdate( 'm/j/Y', $unix_upload_time );
$project_name = $doc->properties->project_id;
if ( array_key_exists( $doc->properties->project_id, $this->projects ) ) {
$project_name = $this->projects[ $doc->properties->project_id ];
}
$doc_properties = array(
'ID' => $count,
'title' => $doc->properties->title,
'extension' => $doc->properties->extension,
'locale' => '<a title=' . $doc->entities[0]->properties->language . '>' . $doc->entities[0]->properties->code . '</a>',
'upload_date' => $upload_date_str,
'project_name' => $project_name,
'id' => $doc->properties->id,
);
$result[] = $doc_properties;
$count++;
}//end foreach
return $result;
}
/**
* This function makes a query to get the documents
*
* @author Unkown
* @uses lingotek-translation/include/api.php/Lingotek_API::get_documents()
* @param Lingotek_API $client used to make the API calls to get the docs
* @param int $per_page default = 10 limits the query to 10 results
* @param int $page_number default = 1 helps to determine the offset
* (so we get the right x amount of documents presented on the current page)
* @return array $docs list of documents returned from the API call get_documents()
*/
function get_docs( $client, $per_page = 10, $page_number = 1 ) {
$limit = $per_page;
$docs = $client->get_documents(
array(
'limit' => $limit,
'offset' => ( ( $page_number - 1 ) * $per_page ),
)
);
return $docs;
}
/**
* Gets the columns for the table to be displayed properly
*
* @author Unkown
* @return array $columns the appropriate columns i18n ready
*/
function get_columns() {
$columns = array(
'cb' => '<input type="checkbox" />',
'title' => __( 'Title', 'lingotek-translation' ),
'extension' => __( 'Extension', 'lingotek-translation' ),
'locale' => __( 'Locale', 'lingotek-translation' ),
'upload_date' => __( 'Upload Date', 'lingotek-translation' ),
'project_name' => __( 'Project Name', 'lingotek-translation' ),
'id' => __( 'ID', 'lingotek-translation' ),
);
return $columns;
}
/**
* This function prepares all the items to be displayed. It calls the get_columns()
* and other supporting funcitons.
*
* @author Unkown and TJ Murphy
* @uses Lingotek_Import_Table::get_columns()
* @uses Lingotek_Import_Table::process_actions()
* @uses Lingotek_Import_Table::get_sortable_columns()
* @uses Lingotek_Import_Table::usort_reorder()
* @see wp-admin/includes/class-wp-list-table.php/WP_List_Table::get_items_per_page()
* @see wp-admin/includes/class-wp-list-table.php/WP_List_Table::get_pagenum()
* @see wp-admin/includes/class-wp-list-table.php/WP_List_Table::set_pagination_args()
* @return void This just sets some variables within the object
*/
function prepare_items() {
/**
*Constant to define how many items per page will show up.
*
*@author TJ Murphy
*/
define( 'LINGOTEK_ITEMS_PER_PAGE', 10 );
$columns = $this->get_columns();
$this->process_actions();
$hidden = array();
$sortable = $this->get_sortable_columns();
$this->_column_headers = array( $columns, $hidden, $sortable );
/**
*Sets the total_items (total number of documents calculated by us) and
*the per_page (how many documents appear on a page dtermined by us)
*
*@see wp-admin/includes/class-wp-list-table.php/WP_List_Table::set_pagination_args()
*/
$this->set_pagination_args(
array(
'total_items' => $this->document_count,
'per_page' => LINGOTEK_ITEMS_PER_PAGE,
)
);
usort( $this->doc_data, array( &$this, 'usort_reorder' ) );
/**
*This slices the documents for the client and only shows the appropriate number
*of documents based on the constant LINGOTEK_ITEMS_PER_PAGE. array_slice takes three
*parameters ($array, $offset, $length)
*
*@author TJ Murphy
*@link http://php.net/manual/en/function.array-slice.php
*/
$this->items = array_slice( $this->doc_data, ( ( LINGOTEK_ITEMS_PER_PAGE * $this->get_pagenum() ) - LINGOTEK_ITEMS_PER_PAGE ), LINGOTEK_ITEMS_PER_PAGE );
}
/**
* This sets the column default. The default for the switch statement shows the
* whole array for troubleshooting purposes
*
* @author Unkown
* @param array $item
* @param string $column_name
* @return string $item[$column_name]
*/
function column_default( $item, $column_name ) {
switch ( $column_name ) {
case 'title':
case 'extension':
case 'locale':
case 'upload_date':
case 'project_name':
case 'id':
return $item[ $column_name ];
default:
return print_r( $item, true );
}
}
/**
* Gets the sortable columns and returns the list
*
* @author Unkown
* @return array $sortable_columns
*/
function get_sortable_columns() {
$sortable_columns = array(
'title' => array( 'title', false ),
'extension' => array( 'extension', false ),
'locale' => array( 'locale', false ),
'upload_date' => array( 'upload_date', false ),
'project_name' => array( 'project_name', false ),
'id' => array( 'id', false ),
);
return $sortable_columns;
}
/**
* Sorts the documents by one of the columns. The default sort is with the Title
* and ascending order. The date sort has its own method to sort, but all other
* columns are sorted the same way.
*
* @author Unknown
* @return int $result direction of sort
* @todo it would be great to make the query that gets the documents do an Order By
* and then this would not even be necessary. It appears this is a limitation in
* the API.
*/
function usort_reorder( $a, $b ) {
$orderby = ( ! empty( $_GET['orderby'] ) ) ? sanitize_text_field( $_GET['orderby'] ) : 'title';
$order = ( ! empty( $_GET['order'] ) ) ? sanitize_text_field( $_GET['order'] ) : 'asc';
$result = 0;
if ( $orderby == 'upload_date' ) {
$date_a = strtotime( $a['upload_date'] );
$date_b = strtotime( $b['upload_date'] );
$result = $date_a - $date_b;
} else {
$result = strcmp( $a[ $orderby ], $b[ $orderby ] );
}
return ( $order === 'asc' ) ? $result : -$result;
}
/**
* Sets the column Title to have the right information in that column. This includes
* the popup link to import the file.
*
* @author Unknown
* @see lingotek-translation/admin/string-actions.php/Lingotek_String_actions::row_actions()
* @return string to be put in the column when displayed
*/
function column_title( $item ) {
$actions = array(
'import' => sprintf(
'<a href="?page=%s&action=%s&post=%s&count=%s&paged=%s">Import</a>',
sanitize_text_field( $_REQUEST['page'] ),
'import',
absint( $item['id'] ),
absint( $this->importedCount ),
absint( $this->get_pagenum() )
),
);
return sprintf( '%1$s %2$s', $item['title'], $this->row_actions( $actions ) );
}
/**
* This just gets the actions that are available for bulk actions
*
* @author Unknown
* @return array $actions available actions to be done on a bulk level
*/
function get_bulk_actions() {
$actions = array(
'import' => 'Import',
);
return $actions;
}
/**
* This function processes any actions (currently the only action is import).
* This includes bulk imports and individual imports. Then it sets the import as
* successful or unsuccessful.
*
* @author Unknown
* @uses Lingotek_Import_Table::add_one_import_success_count()
* @uses Lingotek_Import_Table::add_doc_id_to_unsuccessful_imports()
* @uses Lingotek_Import_Table::import()
* @uses Lingotek_Import_Table::$import_success_count
* @uses Lingotek_Import_Table::$import_status
* @return void this just sets certain variables in the object.
*/
public function process_actions() {
$result = null;
if ( 'import' === $this->current_action() ) {
if ( ! current_user_can( 'import' ) ) {
wp_die( __( 'You do not have sufficient permissions to import documents.', 'lingotek-translation' ) );
}
check_admin_referer( 'bulk-import' );
// Bulk action.
if ( isset( $_POST['post'] ) ) {
foreach ( $_POST['post'] as $doc_id ) {
$doc_id = sanitize_key($doc_id);
$result = $this->import($doc_id);
if ( $result != 0 ) {
$this->add_one_import_success_count();
} else {
$this->add_doc_id_to_unsuccessful_imports( $doc_id );
}
}
} else {
// Single action.
if ( isset( $_GET['action'] ) && sanitize_text_field( $_GET['action'] ) == 'import' ) {
$doc_id = sanitize_key( $_GET['post'] );
$result = $this->import( $doc_id );
if ( $result != 0 ) {
$this->add_one_import_success_count();
} else {
$this->add_doc_id_to_unsuccessful_imports( $doc_id );
}
}
}//end if
/**
*This checks the import_success_count to determine if the import status
*wassuccessful or not. It used to just check if the $result was 0 or not.
*This led to the last bulk import to determine the import status. Now if
*any imports are successful it will mark the import status as successful.
*
*@author TJ Murphy
*@uses Lingotek_Import_Table::$import_success_count
*@uses Lingotek_Import_Table::$import_status
*/
if ( $this->import_success_count > 0 ) {
$this->import_status = 'success';
} else {
$this->import_status = 'failure';
}
}//end if
}
/**
* This converts the many objects and strings that are documents into a format
* that can be imported into WP. If $post_status is not set it gets set to draft.
* If the $post_type is not set then it gets set to post.
*
* @author Unknown
* @uses lingotek-translation/admin/import/StandardImportObject.php/LingotekStandardImportObject
* @uses lingotek-translation/admin/import/StandardImportObject.php/LingotekStandardImportObject::getTitle()
* @uses lingotek-translation/admin/import/StandardImportObject.php/LingotekStandardImportObject::getContent()
* @see wp-admin/includes/class-wp-screen.php/WP_Screen::get_option()
* @link https://developer.wordpress.org/reference/functions/wp_insert_post/
* @param LingotekStandardImportObject $object a document that needs to be converted to
* a standard object that can be imported into WP
* @return int|bool $result 0 or 1 to show if it was successful or not
*/
public function import_standard_object( LingotekStandardImportObject $object ) {
if ( $object->hasError() ) {
return 0;
}
$post_status = get_option( 'lingotek_import_prefs' )['import_post_status'];
$post_type = get_option( 'lingotek_import_prefs' )['import_type'];
if ( ! isset( $post_status ) ) {
$post_status = 'draft';
}
if ( ! isset( $post_type ) ) {
$post_type = 'post';
}
$post_to_import = array(
'post_title' => sanitize_text_field( $object->getTitle() ),
'post_content' => wp_kses_post( $object->getContent() ),
// draft, published, etc.
'post_status' => sanitize_text_field( $post_status ),
// page or post?
'post_type' => sanitize_text_field( $post_type ),
'post_category' => array( 8, 39 ),
);
/**
*@link https://developer.wordpress.org/reference/functions/wp_insert_post/
*/
$result = wp_insert_post( $post_to_import );
return $result;
}
/**
* This function makes the API calls that send a query and get the documents
*
* @author Unknown
* @uses Lingotek_Import_Table::$client
* @uses lingotek-translation/admin/import/FormatConverter.php/Lingotek_FormatConverter
* @uses lingotek-translation/admin/import/FormatConverter.php/Lingotek_FormatConverter::convert_to_standard()
* @uses lingotek-translation/admin/import/FormatConverter.php/Lingotek_FormatConverter::import_standard_object()
*/
public function import( $doc_id ) {
$source_doc = $this->client->get_document( $doc_id );
$content = $this->client->get_document_content( $doc_id );
if ( $content == null ) {
$content == __( 'There is no content to display', 'lingotek-translation' );
}
$format = $source_doc->properties->extension;
$formatConverter = new Lingotek_FormatConverter( $source_doc, $content, $format );
$importObject = $formatConverter->convert_to_standard();
$response = $this->import_standard_object( $importObject );
return $response;
}
/**
* Prints the Column Checkbox
*
* @author Unknown
* @return string the HTML necessary to show the Checkbox
*/
function column_cb( $item ) {
return sprintf( '<input type="checkbox" name="post[]" value="%s" />', esc_attr( $item['id'] ) );
}
/**
* This gets the import status
*
* @author Unknown
* @return string $this->import_status
*/
function get_import_status() {
return $this->import_status;
}
}