Overview

Classes

  • CMLLanguage
  • CMLPost
  • CMLTranslations
  • CMLUtils

Functions

  • cml_dropdown_langs
  • cml_get_browser_lang
  • cml_get_menu
  • cml_get_notice
  • cml_get_the_link
  • cml_is_homepage
  • cml_show_flags
  • Overview
  • Class
  • Tree
   1: <?php
   2: if ( ! defined( 'ABSPATH' ) ) die( "Access denied" );
   3: 
   4: /*
   5:  * Ceceppa Multilingua API 1.4
   6:  */
   7: 
   8:  /**
   9:   * This class provide information about configured languages
  10:   *
  11:   * @api
  12:   * 
  13:   * The structure of language object is:
  14:   * <p>
  15:   * stdClass Object (
  16:   * <ul>
  17:   *   <li>[id] => id of language</li>
  18:   *   <li>[cml_default] => ( boolean ) - is it default?</li>
  19:   *   <li>[cml_flag] => name of flag</li>
  20:   *   <li>[cml_language] => name of language</li>
  21:   *   <li>[cml_language_slug] => language slug</li>
  22:   *   <li>[cml_locale] => wordpress locale</li>
  23:   *   <li>[cml_enabled] => enabled?</li>
  24:   *   <li>[cml_sort_id] => language order</li>
  25:   *   <li>[cml_custom_flag] => (boolean) - use custom flag?</li>
  26:   *   <li>[cml_rtl] => 0</li>
  27:   *   <li>[cml_date_format] => j M Y</li>
  28:   * )
  29:   * </p>
  30:   */
  31: class CMLLanguage {
  32:   /** @ignore */
  33:   private static $_default_language;
  34:   /** @ignore */
  35:   private static $_all_languages; //All languages (enabled and not)
  36:   /** @ignore */
  37:   private static $_all_enabled;   //Only enabled languages
  38:   /** @ignore */
  39:   private static $_all_others;    //All language except default one
  40:   /** @ignore */
  41:   private static $_all_by_slug;   //All languages indexed by slug
  42:   /** @ignore */
  43:   private static $_current_id;    //Current language id
  44: 
  45:   /**
  46:    * Tiny ~= 16x11
  47:    */
  48:   const FLAG_TINY = "tiny";
  49: 
  50:   /**  
  51:    * Small ~= 32x21
  52:    */
  53:   const FLAG_SMALL = "small";
  54: 
  55:   /**
  56:    * return object of default language 
  57:    *
  58:    * @return stdObject
  59:    */
  60:   public static function get_default() {
  61:     if( empty( self::$_all_languages ) ) self::get_all();
  62: 
  63:     return self::$_default_language;
  64:   }
  65: 
  66:   /**
  67:    * return default language id
  68:    *
  69:    * @return int
  70:    */
  71:   public static function get_default_id() {
  72:     return self::get_default()->id;
  73:   }
  74: 
  75:   /**
  76:    * return default language slug
  77:    *
  78:    * return string
  79:    */
  80:   public static function get_default_slug() {
  81:     return self::get_default()->cml_language_slug;
  82:   }
  83:   
  84:   /**
  85:    * return all configured languages, enabled or not...
  86:    *
  87:    * @return stdObject
  88:    */
  89:   public static function get_all() {
  90:     global $wpdb;
  91:   
  92:     /*
  93:      * Prevent a lot of calls to database and store the result into this class
  94:      */
  95:     if( empty( self::$_all_languages) ) {
  96:       self::$_all_languages = $wpdb->get_results( sprintf( "SELECT * FROM %s ORDER BY cml_sort_id ", CECEPPA_ML_TABLE ) );
  97: 
  98:       $all_languages_by_keys = array();
  99:       $sorted = array();
 100:       $enableds = array();
 101:       $byslug = array();
 102:       $others = array();
 103:       foreach( self::$_all_languages as $l ) {
 104:         $all_languages_by_keys[ $l->id ] = $l;
 105:         $byslug[ $l->cml_language_slug ] = $l;
 106:         $sorted[] = $l;
 107: 
 108:         if( $l->cml_default == 1 )
 109:           self::$_default_language = $l;
 110:         else
 111:           $others[ $l->id ] = $l;
 112: 
 113:         if( $l->cml_enabled == 1 ) $enableds[$l->id] = $l;
 114:       }
 115:       
 116:       if( empty( self::$_default_language ) ) {
 117:         update_option( "cml_warning_no_default_language", true );
 118:         
 119:         self::$_default_language = end( $enableds );
 120:       }
 121: 
 122:       self::$_all_enabled = $enableds;
 123:       self::$_all_others = $others;
 124:       self::$_all_languages = $all_languages_by_keys;
 125:       self::$_all_by_slug = $byslug;
 126:       
 127:       if( ! empty( self::$_default_language ) )
 128:         self::$_current_id = self::$_default_language->id;
 129:     }
 130: 
 131:     return self::$_all_languages;
 132:   }
 133: 
 134:   /**
 135:    * return all configured languages except default one
 136:    *
 137:    * @return stdObject
 138:    */
 139:   public static function get_no_default() {
 140:     if( empty( self::$_all_languages) ) self::get_all();
 141:     
 142:     return self::$_all_others;
 143:   }
 144: 
 145:   /**
 146:    * return all enabled languages
 147:    *
 148:    * @return stdObject
 149:    */
 150:   public static function get_enableds() {
 151:     if( empty( self::$_all_languages ) ) self::get_all();
 152:     
 153:     return self::$_all_enabled;
 154:   }
 155: 
 156:   /*
 157:    * return all enabled languages except current one
 158:    *
 159:    * @param boolean $only_enableds return only enabled languages
 160:    * @return stdObject
 161:    */
 162:   public static function get_others( $only_enableds = true ) {
 163:     if( empty( self::$_all_languages ) ) self::get_all();
 164:     
 165:     $langs = ( $only_enableds ) ? self::$_all_enabled : self::$_all_languages;
 166:     unset( $langs[ self::get_current_id() ] );
 167:     
 168:     return $langs;
 169:   }
 170: 
 171:   /**
 172:    * return associative array where index
 173:    * is the language slug
 174:    *
 175:    * @example
 176:    * Array (
 177:    * <ul>
 178:    *   <li>"it" => [stdObject..],</li>
 179:    *   <li>"en" => [stdObject...]</li>
 180:    * </ul>
 181:    * )
 182:    *
 183:    * @return Array
 184:    */
 185:   public static function get_slugs() {
 186:     if( empty( self::$_all_languages ) ) self::get_all();
 187:     
 188:     return self::$_all_by_slug;
 189:   }
 190: 
 191:   /**
 192:    * return current language
 193:    *
 194:    * @return stdobject
 195:    */
 196:   public static function get_current() {
 197:     if( empty( self::$_all_languages ) ) self::get_all();
 198:     
 199:     return self::$_all_languages[ self::$_current_id ];
 200:   }
 201: 
 202:   /**
 203:    * return current language id
 204:    *
 205:    * @return int
 206:    */
 207:   public static function get_current_id() {
 208:     return self::get_current()->id;
 209:   }
 210: 
 211:   /**
 212:    * return current language slug
 213:    */
 214:   public static function get_current_slug() {
 215:     return self::get_current()->cml_language_slug;
 216:   }
 217: 
 218:   /**
 219:    * return the name of language
 220:    *
 221:    * @param int/string $lang - id or slug of language
 222:    *
 223:    * @return string
 224:    */
 225:   public static function get_name( $lang ) {
 226:     if( empty( self::$_all_languages ) ) self::get_all();
 227:     if( empty( self::$_default_language ) ) self::get_default();
 228:     if( ! is_numeric( $lang ) ) $lang = self::get_id_by_slug( $lang );
 229: 
 230:     return self::$_all_languages[ $lang ]->cml_language;
 231:   }
 232: 
 233:   /**
 234:    * return the slug of language
 235:    *
 236:    * @param int/string $lang - id or slug of language
 237:    *
 238:    * @return string
 239:    */
 240:   public static function get_slug( $lang ) {
 241:     if( empty( self::$_all_languages ) ) self::get_all();
 242:     if( empty( self::$_default_language ) ) self::get_default();
 243:     if( is_object( $lang ) ) $lang = $lang->id;
 244: 
 245:     if( $lang == 0 ) return self::$_default_language->cml_language_slug;
 246: 
 247:     return @self::$_all_languages[ $lang ]->cml_language_slug;
 248:   }
 249: 
 250:   /**
 251:    * return language by id
 252:    *
 253:    * @param int/string $lang id or slug of language to search
 254:    *
 255:    * @return stdObject
 256:    */
 257:   public static function get_by_id( $id ) {
 258:     if( empty( self::$_all_languages ) ) self::get_all();
 259:     if( ! is_numeric( $id ) ) $id = CMLLanguage::get_by_slug( $id );
 260: 
 261:     return self::$_all_languages[ $id ];
 262:   }
 263: 
 264:   /**
 265:    * get language by slug
 266:    *
 267:    * @param string $slug - language slug
 268:    * @param boolean $empty - If false return default language if $slug doesn't exists.
 269:    *                           If true and $slug doesn't exists return empty array
 270:    *
 271:    * @return stdObject
 272:    */
 273:   public static function get_by_slug( $slug, $empty = false ) {
 274:     if( empty( self::$_all_languages ) ) self::get_all();
 275: 
 276:     foreach( self::$_all_languages as $lang ) {
 277:       if( $lang->cml_language_slug == $slug ) return $lang;
 278:     }
 279:     
 280:     return ( ! $empty ) ? self::get_default() : array();
 281:   }
 282: 
 283:   /**
 284:    * return language id by slug
 285:    *
 286:    * @param string $slug - language slug
 287:    *
 288:    * @return int
 289:    */
 290:   public static function get_id_by_slug( $slug ) {
 291:     $lang = self::get_by_slug( $slug );
 292: 
 293:     return $lang->id;
 294:   }
 295: 
 296:   /**
 297:    * return language id by locale
 298:    *
 299:    * @param string $language locale
 300:    *
 301:    * @return int
 302:    */
 303:   public static function get_id_by_locale( $locale ) {
 304:     $langs = self::get_all();
 305:     
 306:     foreach( $langs as $lang ) {
 307:       if( $lang->cml_locale == $locale ) return $lang;
 308:     }
 309:     
 310:     return null;
 311:   }
 312: 
 313:   /**
 314:    * return the flag filename ( withouth extension )
 315:    *
 316:    * @param int/string $lang ( optional ) - id/slug of language, if empty default one will be used
 317:    * @param string $size ( optional ) - size of flag: "tiny" or "small"
 318:    *
 319:    * @return string
 320:    */
 321:   public static function get_flag( $lang = null, $size = "small" ) {
 322:     if( empty( $lang ) ) $lang = self::default_language_id();
 323:     if( ! is_numeric( $lang ) ) $lang = self::get_id_by_slug( $lang );
 324: 
 325:     if( empty( self::$_all_languages ) ) self::get_all();
 326: 
 327:     return self::$_all_languages[ $lang ]->cml_flag;
 328:   }
 329: 
 330:   /**
 331:    * return flag filename with the full path.
 332:    *
 333:    * Example
 334:    * www.example.com/wp-content/plugin/ceceppa-multilingua/flags/tiny/it_IT.png
 335:    *
 336:    * @param int/string $lang ( optional ) - id or slug of language, if empty default one will be used
 337:    * @param string $size ( optional ) - size of flag: "tiny" or "small"
 338:    *
 339:    * @return string: flag filename with the full path.
 340:    */
 341:   public static function get_flag_src( $lang = null, $size = CML_FLAG_TINY ) {
 342:     if( empty( self::$_all_languages ) ) self::get_all();
 343:     if( empty( self::$_default_language ) ) self::get_default();
 344:     if( $lang == null ) $lang = self::get_default_id();
 345:     if( ! is_numeric( $lang ) ) $lang = self::get_id_by_slug( $lang );
 346: 
 347:     $lang = self::$_all_languages[ $lang ];
 348:     $flag = $lang->cml_flag;
 349: 
 350:     if( $lang->cml_custom_flag == 1 && file_exists( CML_UPLOAD_DIR . "/$size/$flag.png" ) )
 351:       $url = CML_UPLOAD_URL . "/$size/$flag.png";
 352:     else
 353:       $url = CML_PLUGIN_URL . "flags/$size/$flag.png";
 354: 
 355:     return esc_url( $url );
 356:   }
 357:   
 358:   /**
 359:    * return html <img> object of flag
 360:    *
 361:    * @param int/string $lang - id or slug of language
 362:    * @param string $size - flag size ( tiny or small )
 363:    *
 364:    * @return string
 365:    */
 366:   public static function get_flag_img( $lang, $size = CML_FLAG_TINY ) {
 367:     $url = self::get_flag_src( $lang, $size );
 368:     $name = self::get_name( $lang );
 369:     $slug = self::get_slug( $lang );
 370: 
 371:     return "<img src='$url' border='0' alt='$slug' title='$name' />";
 372:   }
 373:    
 374:    /**
 375:     * @ignore
 376:     *
 377:     * force "reload" languages
 378:     */
 379:    public static function reload() {
 380:     self::$_all_languages = null;
 381:    }
 382: 
 383:   /**
 384:    * get language object by post id
 385:    *
 386:    * @param int $post_id - id of post/page
 387:    *
 388:    * @return stdObject
 389:    */
 390:   public static function get_by_post_id( $post_id ) {
 391:     return CMLPost::get_language_by_id( $post_id );
 392:   }
 393: 
 394:   /**
 395:    * get language id by post id
 396:    *
 397:    * @param int $post_id - id of post
 398:    *
 399:    * @return int
 400:    */
 401:   public static function get_id_by_post_id( $post_id ) {
 402:     return CMLPost::get_language_id_by_id( $post_id );
 403:   }
 404:   
 405:   /**
 406:    * Is $lang the default one?
 407:    *
 408:    * @param int/string $lang ( optional ) id/slug. check if $lang is the default language, if null is passed
 409:    *                        current language will be assumed
 410:    * @return boolean
 411:    */
 412:   public static function is_default( $lang = null) {
 413:     if( null == $lang ) {
 414:       $lang = CMLLanguage::get_current_id();
 415:     } else {
 416:       if( ! is_numeric( $lang ) ) {
 417:         $lang = CMLLanguage::get_id_by_slug( $lang );
 418:       }
 419:     }
 420: 
 421:     return $lang == CMLLanguage::get_default_id();
 422:   }
 423:  
 424:   /**
 425:    * check if $lang is the current language
 426:    *
 427:    * @param int/string $lang language id/slug to compare
 428:    *
 429:    * @return boolean
 430:    */
 431:   public static function is_current( $lang ) {
 432:     if( null == $lang ) {
 433:       $lang = CMLLanguage::get_current_id();
 434:     } else {
 435:       if( ! is_numeric( $lang ) ) {
 436:         $lang = CMLLanguage::get_id_by_slug( $lang );
 437:       }
 438:     }
 439:     
 440:     return $lang == CMLLanguage::get_current_id();
 441:   }
 442: 
 443:   /**
 444:    * @ignore
 445:    * 
 446:    * set current language
 447:    *
 448:    * @param $lang - language object or id
 449:    *
 450:    * @return void
 451:    */
 452:   public static function set_current( $lang ) {
 453:     $id = is_object( $lang ) ? $lang->id : $lang;
 454:     
 455:     self::$_current_id = $id;
 456:   }
 457: }
 458: 
 459: /**
 460:  * This class is used to get and store custom translations in CECEPPA_ML_TRANSLATIONS table.
 461:  */
 462: class CMLTranslations {
 463:   //store "get" translations
 464:   /** @ignore */
 465:   private static $_translations = array();
 466:   /** @ignore */
 467:   private static $_keys = array();
 468: 
 469:   /**
 470:    * This function can be used by 3rd part plugin/theme to allow translation of its strings.
 471:    * Added string can be translated in "My Languages" page.
 472:    *
 473:    * @example
 474:    * Full example is provided here:<br />
 475:    *  http://www.alessandrosenese.eu/en/ceceppa-multilingua/extend-plugin-theme-compatibility/
 476:    *
 477:    * @param string $key used to store/get your own value from database. To avoid duplicated key use your own
 478:    *                        prefix for your key. Example: "_yoast_rssafter"
 479:    * @param string $default default value to use
 480:    * @param string $group The group name of your own strings, this name will be displayed in "My Translations" page
 481:    *                      in "Group" column. Group name should be preceded by "_" symbol.<br />
 482:    *                      Example: "_YOAST"
 483:    *
 484:    * @return void
 485:    */
 486:   public static function add( $key, $default, $group ) {
 487:     global $wpdb;
 488: 
 489:     $default = bin2hex( $default );
 490:     foreach( CMLLanguage::get_all() as $lang ) {
 491:       $query = sprintf( "SELECT id FROM %s WHERE cml_text = '%s' AND cml_lang_id = %d AND cml_type = '%s'",
 492:                         CECEPPA_ML_TRANSLATIONS,
 493:                         bin2hex( strtolower( $key ) ),
 494:                         $lang->id,
 495:                         $group );
 496:   
 497:       $record = $wpdb->get_var( $query );
 498:       if( empty( $record ) ) {
 499:         $wpdb->insert( CECEPPA_ML_TRANSLATIONS,
 500:                       array(
 501:                             'cml_text' => bin2hex( strtolower( $key ) ),
 502:                             'cml_lang_id' => $lang->id,
 503:                             'cml_translation' => $default,
 504:                             'cml_type' => $group
 505:                             ),
 506:                       array(
 507:                         '%s', '%d', '%s', '%s',
 508:                       )
 509:                      );
 510:       }
 511:     }
 512:   }
 513:   
 514:   /**
 515:    * Store custom translation in database.
 516:    *
 517:    * Since 1.4 CML generate GNUTEXT mo file from stored translations. 
 518:    * The domain used to generate translation is: "cmltrans".
 519:    *
 520:    * Mo file isn't generated automatically, but you have to call manually
 521:    * the function cml_generate_mo_from_translations()
 522:    * 
 523:    * This function will return the id of inserted record.
 524:    * 
 525:    * @example
 526:    *
 527:    * <?php _e( "Hello", "cmltrans" ); ?>
 528:    *
 529:    * Use "get" function instead of __, _e, because if "mo" generation fails,
 530:    * this function will get translation from database
 531:    * 
 532:    * @param int/string $lang - id/slug of language
 533:    * @param string $original - original string
 534:    * @param string $translation - translated string
 535:    * @param string $type - type of translation( W: Widget, S: Custom strings ).
 536:    *                Type field is used "internally" to show records in correct table, like
 537:    *                Widget titles, My translations...
 538:    *
 539:    * @return string
 540:    */
 541:   public static function set( $lang, $original, $translated, $type ) {
 542:     global $wpdb;
 543: 
 544:     if( ! is_numeric( $lang ) ) $lang = CMLLanguage::get_id_by_slug( $lang );
 545: 
 546:     $wpdb->delete( CECEPPA_ML_TRANSLATIONS,
 547:                     array( "cml_text" => bin2hex( $original ),
 548:                            "cml_type" => $type,
 549:                            "cml_lang_id" => $lang ),
 550:                     array( "%s", "%s", "%d" ) );
 551: 
 552:     return $wpdb->insert( CECEPPA_ML_TRANSLATIONS, 
 553:                           array( 'cml_text' => bin2hex( $original ),
 554:                                 'cml_lang_id' => $lang,
 555:                                 'cml_translation' => bin2hex( $translated ),
 556:                                 'cml_type' => $type ),
 557:                           array( '%s', '%d', '%s', '%s' ) );
 558:   }
 559:   
 560:   /**
 561:    * return translation stored in cml_trans table.
 562:    *
 563:    * This function will get translation from ".mo" file if:
 564:    *    1) it's generated correctly
 565:    *    2) $lang == current language
 566:    *
 567:    * otherwise will get translation from database
 568:    *
 569:    * <strong>string match is case sensitive</strong>
 570:    * 
 571:    * @param int/string $lang - language id or slug
 572:    * @param string $string - string to translate
 573:    * @param string $type - ( optional ) This is used internally by Ceceppa Multilingua, only in admin interface
 574:    *                  T - Site Title/Tagline,
 575:    *                  W - Widget,
 576:    *                  M - My translations
 577:    *                  
 578:    * @param boolean $return_empty - If true, return empty string if no translation is found
 579:    * @param boolean $ignore_po  Since 1.4 the plugin will generate mo file for all translation stored
 580:    *                                in CECEPPA_ML_TRANSLATIONS ( widget titles, my translations, site title/tagline... ).
 581:    *                                So by default if $lang == current language, the plugin will get translation
 582:    *                                from ".mo" file instead query the database.
 583:    *                                You can force to retive translation from database.
 584:    *
 585:    * @return string                 
 586:    */
 587:   public static function get( $lang, $string, $type = "", $return_empty = false, $ignore_po = false ) {
 588:     global $wpdb;
 589: 
 590:     if( "_" == $type[ 0 ] && ! $return_empty ) {
 591:       $return_empty = true;
 592:     }
 593: 
 594:     //C = Category
 595:     $s = ( $type == "C" ) ? strtolower( $string ) : $string;
 596: 
 597:     //Look if I already translated it...
 598:     if( isset( self::$_keys[ $lang ] ) && in_array( sanitize_title( $s ), self::$_keys[ $lang ] ) ) {
 599:       $index = array_search( sanitize_title( $s ), self::$_keys[ $lang ] );
 600:       return self::$_translations[ $lang ][ $index ];
 601:     }
 602: 
 603:     if( CML_GET_TRANSLATIONS_FROM_PO &&
 604:        ! $ignore_po &&
 605:          file_exists( "cmltrans-" . CMLLanguage::get_current()->cml_locale ) ) {
 606:       $ret = __( $s, 'cmltrans' );
 607:       //if( $ret == $s ) { //Failed?
 608:         //return $string;
 609:       //}
 610:     }
 611: 
 612:     if( ! is_numeric( $lang ) ) {
 613:       $lang = CMLLanguage::get_id_by_slug( $lang );
 614:     }
 615: 
 616:     $query = sprintf(" SELECT UNHEX(cml_translation) FROM %s WHERE cml_text = '%s' AND cml_lang_id = %d AND cml_type LIKE '%s'",
 617:                                     CECEPPA_ML_TRANSLATIONS, bin2hex( $s ), $lang, "%" . $type . "%" );
 618: 
 619:     $return = $wpdb->get_var( $query );
 620: 
 621:     if( $return_empty && empty( $return ) ) return "";
 622: 
 623:     $return = ( empty( $return ) ) ?  $string : html_entity_decode( stripslashes( $return ) );
 624:     
 625:     self::$_translations[$lang][] = $return;
 626:     self::$_keys[ $lang ][] = sanitize_title( $string );
 627: 
 628:     return $return;
 629:   }
 630:   
 631:   /*
 632:    * get translation from wordpress
 633:    *
 634:    * @ignore
 635:    */
 636:   public static function gettext( $lang, $string, $type, $ignore_po = false ) {
 637:     $ret = self::get( $lang, $string, $type, true, $ignore_po );
 638: 
 639:     if( ! empty( $ret ) ) return $ret;
 640: 
 641:     //Recupero la traduzione dalle frasi di wordpress ;)
 642:     require_once( CML_PLUGIN_PATH . "gettext/gettext.inc" );
 643:     
 644:     $locale = CMLLanguage::get_current()->cml_locale;
 645: 
 646:     // gettext setup
 647:     T_setlocale( LC_MESSAGES, $locale );
 648:     // Set the text domain as 'messages'
 649: 
 650:     $domain = $locale;
 651:     T_bindtextdomain( $domain, CML_WP_LOCALE_DIR );
 652:     T_bind_textdomain_codeset( $domain, 'UTF-8' );
 653:     T_textdomain( $domain );
 654: 
 655:     $ret = T_gettext( $string );
 656: 
 657:     return ( empty( $ret ) ) ?  $string : html_entity_decode( stripslashes( $ret ) );
 658:   }
 659:   
 660:   /**
 661:    * delete all records with cml_type = xx
 662:    *
 663:    * @ignore
 664:    */
 665:   public static function delete( $type ) {
 666:     global $wpdb;
 667:     
 668:     $wpdb->delete( CECEPPA_ML_TRANSLATIONS,
 669:                   array( "cml_type" => $type ),
 670:                   array( "%s" ) );
 671:   }
 672: }
 673: 
 674: /**
 675:  * This class is used to get/set post translation/language or get language by its id
 676:  * 
 677:  */
 678: class CMLPost {
 679:   /** @ignore */
 680:   private static $_indexes = null;
 681:   /** @ignore */
 682:   private static $_posts_meta = null;
 683: 
 684:   /**
 685:    * return language object by post id
 686:    *
 687:    * this function return "null" if post doesn't exists in any language
 688:    * 
 689:    * @param int/string $post_id - id of post/page
 690:    *
 691:    * @return stdObject
 692:    */
 693:   public static function get_language_by_id( $post_id ) {
 694:     if( empty( self::$_indexes ) ) self::_load_indexes();
 695: 
 696:     /*
 697:      * search in current language first.
 698:      * because if post exists in multiple languages, included current one,
 699:      * I have to return current language id, not random :)
 700:      */
 701:     if( @in_array( $post_id, self::$_indexes[ CMLLanguage::get_current_id() ] ) ) {
 702:       return CMLLanguage::get_current();
 703:     }
 704: 
 705:     foreach( CMLLanguage::get_others() as $lang ) {
 706:       if( @in_array( $post_id, self::$_indexes[ $lang->id ] ) )
 707:         return $lang;
 708:     }
 709: 
 710:     return null;
 711:   }
 712:   
 713:   /**
 714:    * return language id by post id
 715:    *
 716:    * @param int $post_id - id of post/page
 717:    * @param boolean $meta - default false.
 718:    *                        If true use wp function "get_post_meta", instead of get_language_by_id method
 719:    *                        to get language of post.
 720:    *                        In backend I need to get information by post meta, or I'll lost
 721:    *                        "all languages" ( = 0 ) information.
 722:    *
 723:    * @return int
 724:    */
 725:   public static function get_language_id_by_id( $post_id, $meta = false ) {
 726:     if( $meta ) {
 727:       //Get from meta
 728:       $meta = get_post_meta( $post_id, "_cml_meta", true );
 729:       
 730:       if( ! empty( $meta ) && isset( $meta[ "lang" ] ) ) {
 731:         return $meta[ "lang"];
 732:       }
 733:     }
 734: 
 735:     $lang = self::get_language_by_id( $post_id );
 736: 
 737:     if( null === $lang ) {
 738:       //Get from meta
 739:       $meta = get_post_meta( $post_id, "_cml_meta", true );
 740:       
 741:       if( empty( $meta ) ) {
 742:         $lang = self::get_language_by_id( $post_id );
 743:   
 744:         if( is_object( $lang ) ) {
 745:           //update meta
 746:           self::update_meta( $lang->id, $post_id );
 747:         }
 748:   
 749:         return is_object( $lang ) ? $lang->id : 0;
 750:       } else {
 751:         return @$meta[ "lang" ];
 752:       }
 753:     }
 754:     
 755:     return $lang->id;
 756:   }
 757:   
 758:   /**
 759:    * get language slug by post id
 760:    *
 761:    * @param int $post_id post/page id
 762:    *
 763:    * @return string
 764:    */
 765:   public static function get_language_slug_by_id( $post_id ) {
 766:     $lang = self::get_language_by_id( $post_id );
 767:     
 768:     return is_object( $lang ) ? $lang->cml_language_slug : "";
 769:   }
 770: 
 771:   /**
 772:    * get the translation id, if exists, in selected language
 773:    *
 774:    * this function will return 0 if no translation is found.
 775:    * 
 776:    * @param int/string $lang - language id/slug in which return translation
 777:    * @param int $post_id - post id
 778:    *
 779:    * @return int
 780:    */
 781:   public static function get_translation( $lang, $post_id ) {
 782:     global $wpdb;
 783: 
 784:     if( is_numeric( $lang ) ) $lang = CMLLanguage::get_slug( $lang );
 785:     if( empty( $post_id ) ) return 0;
 786: 
 787:     //if( ! CECEPPA_ML_MIGRATED ) {
 788:     //  return cml_old_get_linked_post( $wpCeceppaML->get_language_id_by_post_id( $post_id ), null, $post_id, $lang );
 789:     //}
 790:   
 791:     $linked = self::get_translations( $post_id );
 792: 
 793:     return ( ! array_key_exists( $lang, $linked) ) ? 0 : $linked[ $lang ];
 794:   }
 795: 
 796:   /**
 797:    * get all available translations of post
 798:    *
 799:    * This function will return Array containing all info about linked posts
 800:    *
 801:    * Array(
 802:    * <ul>
 803:    *   <li>[language slug] => [post_id]</li>
 804:    *   <li>...</li>
 805:    *   <li>[indexes] => Array<br />
 806:    *    <i>In this subarray there are all linked posts, including $post_id</i>
 807:    *    <ul>
 808:    *      <li>[language slug] => [post_id]</li>
 809:    *      <li>...</li>
 810:    *    </ul>
 811:    *   </li>
 812:    *   <li>
 813:    *    [linked] => Array<br />
 814:    *    <i>In this subarray there are only linked post indexes</i> 
 815:    *    <ul>
 816:    *      <li>[linked language slug] => [linked_id]</li>
 817:    *      <li>...</li>
 818:    *    </ul>
 819:    *  </li>
 820:    * </ul>
 821:    * )
 822:    * 
 823:    * @example
 824:    * <br />
 825:    * Array (
 826:    * <ul>
 827:    *   <li>[it] => 2552</li>
 828:    *   <li>[en] => 541</li>
 829:    *   <li>[eo] => 0</li>
 830:    *   <li>[indexes] => Array
 831:    *       (
 832:    *       <ul>
 833:    *        <li>[it] => 2552</li>
 834:    *       </ul>
 835:    *       )
 836:    *    </li>
 837:    *    <li>
 838:    *   [others] => Array
 839:    *       (
 840:    *       <ul>
 841:    *        <li>[en] => 541</li>
 842:    *       )
 843:    *    </li>
 844:    *  </ul>
 845:    * )
 846:    *
 847:    * @param int $post_id - post id
 848:    * @param boolean $force - force to rebuild meta. ( This parameter is used internally by CML )
 849:    *
 850:    * return Array
 851:    */
 852:   public static function get_translations( $post_id, $force = false ) {
 853:     global $wpdb;
 854:   
 855:     if( empty( $post_id ) ) return array();
 856: 
 857:     if( ! isset( self::$_posts_meta[ $post_id ] ) || $force ) {
 858:       //if( ! CECEPPA_ML_MIGRATED ) return cml_old_get_linked_posts( $id );
 859:       if( empty( $GLOBALS[ '_cml_language_columns' ] ) ) {
 860:         cml_generate_lang_columns();
 861:       }
 862:     
 863:       $_cml_language_columns = & $GLOBALS[ '_cml_language_columns' ];
 864:       $_conv = & $GLOBALS[ '_cml_language_keys' ];
 865:     
 866:       $query = "SELECT ";
 867:       foreach( $_conv as $key => $label ) {
 868:         $select[] = "$key as $label";
 869:       }
 870:       $query .= join( ",", $select ) . " FROM " . CECEPPA_ML_RELATIONS . " WHERE ";
 871:       foreach( $_cml_language_columns as $l ) {
 872:         $where[] = "$l = $post_id";
 873:       }
 874:       $query .= join( " OR ", $where );
 875:     
 876:       $row = $wpdb->get_row( $query, ARRAY_A );
 877:       unset( $row[ "id" ] );
 878:     
 879:       $keys = @array_filter( $row );
 880:       $keys = @array_replace( $keys, $_conv );
 881:       $others = @array_filter( is_array( $row ) ? $row : array() );
 882:       unset( $others[ CMLPost::get_language_slug_by_id( $post_id ) ] );
 883:     
 884:       $row = @array_merge( (array) $row, array( "indexes" => array_filter( $row ),
 885:                                                "linked" => $others ) );
 886:       
 887:       self::$_posts_meta[ $post_id ] = $row;
 888:     } else {
 889:       $row = self::$_posts_meta[ $post_id ];
 890:     }
 891: 
 892:     return $row;
 893:   }
 894:   
 895:   /**
 896:    * set language of post
 897:    *
 898:    * This function will unlink $post_id by its translations
 899:    * 
 900:    * @param int/string $lang - post language id/slug 
 901:    * @param int $post_id - post id
 902:    */
 903:   public static function set_language( $lang, $post_id ) {
 904:     if( ! is_numeric( $lang ) ) $lang = CMLLanguage::get_id_by_slug( $lang );
 905: 
 906:     cml_migrate_database_add_item( $lang, $post_id, 0, 0 );
 907:   }
 908: 
 909:   /**
 910:    * set single translation to post id
 911:    *
 912:    * This function is used to link 2 posts
 913:    *
 914:    * When you link a post to single translation, relations with other language will not be losed.
 915:    * If you want remove other relations, you have to use set_language method first.
 916:    * 
 917:    * @param int $post_id - post to set translation
 918:    * @param int/string $linked_lang - language id/slug of linked post
 919:    * @param int $linked_post - post id of translation
 920:    * @param int $post_lang ( optional ) - language of $post_id. If null, It will get from database
 921:    *
 922:    * @return void
 923:    */
 924:   public static function set_translation( $post_id, $linked_lang, $linked_post, $post_lang = null ) {
 925:     self::set_translations( $post_id, array( $linked_lang => $linked_post ), $post_lang );
 926:   }
 927: 
 928:   /**
 929:    * add multiple translations to post id
 930:    *
 931:    * This function will update relations only from $post_id with $translations posts, so relations
 932:    * from $post_id and languages than doesn't exists in $translations array will not be broken.
 933:    * 
 934:    * If you need to set relation only from $post_id and $translations, and remove the other one, you
 935:    * have to "break" them using set_language method first.
 936:    * 
 937:    * @param $post_id - post to set translation+
 938:    * @param $translations - array with language_slug as key and post_id as value.
 939:    *                        array( "it" => 1, "en" => 2 )...
 940:    * @param $post_lang ( optional ) - set also the language of $post_id
 941:    *
 942:    * @example:
 943:    *
 944:    *    CMLPost::set_translation( 1, array( "it" => 2, "en" => 3 ) )
 945:    */
 946:   public static function set_translations( $post_id, $translations, $post_lang = null ) {
 947:     //$_cml_language_columns = & $GLOBALS[ '_cml_language_columns' ];
 948:     if( null === $post_lang ) $post_lang = CMLPost::get_language_id_by_id( $post_id );
 949: 
 950:     foreach( $translations as $key => $id ) {
 951:       if( ! is_numeric( $key ) ) $key = CMLLanguage::get_by_slug( $key );
 952: 
 953:       cml_migrate_database_add_item( $post_lang, $post_id, $key, $id );
 954:     }
 955: 
 956:     //Update info
 957:     cml_fix_rebuild_posts_info();
 958:     self::_load_indexes();
 959:     
 960:     self::update_meta( $post_lang, $post_id );
 961:   }
 962:   
 963:   /*
 964:    * update post meta
 965:    * @ignore
 966:    */
 967:   public static function update_meta( $lang, $post_id ) {
 968:     /*
 969:      * I just updated post relation, so I have to rebuild meta :)
 970:      */
 971:     //Add my meta to post
 972:     $meta = array( "lang" => $lang,
 973:                     "translations" => CMLPost::get_translations( $post_id, true ) );
 974: 
 975:     //print_r( $meta );
 976:     //die();
 977:     update_post_meta( $post_id, "_cml_meta", $meta );
 978:   }
 979: 
 980:   /**
 981:    * get indexes of posts that exists in selected language
 982:    *
 983:    * @param int/slug $lang ( optional, if not set will be = current language id )
 984:    *                      id / slug of language
 985:    *
 986:    * @return array
 987:    */
 988:   public static function get_posts_by_language( $lang = null ) {
 989:     if( empty( $lang ) ) $lang = CMLLanguage::get_current_id();
 990:     if( ! is_numeric( $lang ) ) $lang = CMLLanguage::get_id_by_slug( $lang );
 991:   
 992:     //Gli articoli senza lingua sono "figli di tutti"
 993:     if( empty( self::$_indexes ) ) self::_load_indexes();
 994: 
 995:     $posts = @self::$_indexes[ $lang ];
 996: 
 997:     return ! empty( $posts ) ? array_unique( $posts ) : array();
 998:   }
 999: 
1000:   /*
1001:    * for private use only, update post indexes by language
1002:    * @ignore
1003:    */
1004:   public static function _update_posts_by_language( $lang, $ids ) {
1005:     self::$_indexes[ $lang ] = $ids;
1006:   }
1007: 
1008:   /**
1009:    * return all posts by languages.
1010:    *
1011:    * The key of array is the language id
1012:    *
1013:    * @return array
1014:    */
1015:   public static function get_posts_by_languages() {
1016:     //Gli articoli senza lingua sono "figli di tutti"
1017:     if( empty( self::$_indexes ) ) self::_load_indexes();
1018: 
1019:     return self::$_indexes;
1020:   }
1021: 
1022:   /**
1023:    * check if $post_id has translation in selected language.
1024:    *
1025:    * @param int/string $lang - language id/slug
1026:    * @param int $post_id - post id
1027:    * 
1028:    * return boolean
1029:    */
1030:   public static function has_translation( $lang, $post_id ) {
1031:     if( ! isset( self::$_posts_meta[ $post_id ] ) ) {
1032:       self::$_posts_meta[ $post_id ] = self::get_translations( $post_id );
1033:     }
1034: 
1035:     if( is_numeric( $lang ) ) $lang = CMLLanguage::get_slug( $lang );
1036: 
1037:     return ( isset( self::$_posts_meta[ $post_id ]['indexes'] ) &&
1038:             self::$_posts_meta[ $post_id ]['indexes'][ $lang ] > 0 );
1039:   }
1040: 
1041:   /**
1042:    * check if $post_id has any translation
1043:    *
1044:    * @param int $post_id - post id
1045:    *
1046:    * @return boolean
1047:    */
1048:   public static function has_translations( $post_id ) {
1049:     if( ! isset( self::$_posts_meta[ $post_id ] ) ) {
1050:       self::$_posts_meta[ $post_id ] = self::get_translations( $post_id );
1051:     }
1052: 
1053:     return ! empty( self::$_posts_meta[ $post_id ][ 'linked' ] );
1054:   }
1055: 
1056:   /** @ignore */
1057:   private static function _load_indexes() {
1058:     $langs = cml_get_languages( false );
1059: 
1060:     foreach($langs as $lang) {
1061:       self::$_indexes[ $lang->id ] = get_option( "cml_posts_of_lang_" . $lang->id );
1062:     }
1063:   }
1064: 
1065: }
1066: 
1067: /**
1068:  * utility class
1069:  *
1070:  */
1071: class CMLUtils {
1072:   /** @ignore */
1073:   private static $_permalink_structure;
1074:   /** @ignore */
1075:   private static $_url_mode;
1076:   /** @ignore */
1077:   private static $_date_format;
1078:   /** @ignore */
1079:   private static $_home_url;
1080:   /** @ignore */
1081:   private static $_clean_url;
1082:   /** @ignore */
1083:   private static $_clean_request;
1084:   /** @ignore */
1085:   private static $_request_url;
1086:   /** @ignore */
1087:   private static $_clean_applied = false;
1088:   /** @ignore */
1089:   private static $_url;
1090:   /** @ignore */
1091:   private static $_language_detected = null;
1092:   /** @ignore */
1093:   private static $_vars = array();
1094: 
1095:   /**
1096:    * @ignore
1097:    * 
1098:    * return wordpress permalink structure option
1099:    *
1100:    * @return string
1101:    */
1102:   public static function get_permalink_structure() {
1103:     if( ! isset( self::$_permalink_structure ) ) self::$_permalink_structure = get_option( "permalink_structure" );
1104:     
1105:     return self::$_permalink_structure;
1106:   }
1107:   
1108:   /**
1109:    * return home_url link in according to language slug.
1110:    *
1111:    * This function format home_url in according to $slug parameter
1112:    *
1113:    * @param string $slug - language slug. If null current slug will be used
1114:    *
1115:    * @return string
1116:    */
1117:   public static function get_home_url( $slug = null ) {
1118:     $_cml_settings = & $GLOBALS[ '_cml_settings' ];
1119: 
1120:     if( null === $slug ) $slug = CMLLanguage::get_default()->cml_language_slug;
1121: 
1122:     switch( CMLUtils::get_url_mode() ) {
1123:     case PRE_PATH:
1124:       if( $slug == CMLLanguage::get_default()->cml_language_slug &&
1125:           $_cml_settings[ 'url_mode_remove_default' ] ) {
1126:         $slug = "";
1127:       } else
1128:         $slug = "/$slug";
1129: 
1130:       $link = CMLUtils::home_url() . $slug;
1131:       break;
1132:     case PRE_DOMAIN:
1133:       $link = CMLUtils::home_url();
1134:       break;
1135:     default:
1136:       $link = CMLUtils::home_url() . "?lang=$slug";
1137:       break;
1138:     } //endswitch;
1139: 
1140:     return $link;
1141:   }
1142: 
1143:   /**
1144:    * @ignore
1145:    */
1146:   public static function get_url_mode() {
1147:     if( empty( self::$_url_mode ) )  {
1148:       global $_cml_settings;
1149:     
1150:       self::$_url_mode = $_cml_settings[ 'url_mode' ];  //more easy
1151:       
1152:       $permalink = self::get_permalink_structure();
1153:       if( empty( $permalink ) && self::$_url_mode == PRE_PATH )
1154:         self::$_url_mode = PRE_LANG;
1155:     }
1156: 
1157:     return self::$_url_mode;
1158:   }
1159:   
1160:   /**
1161:    * get wordpress date format option
1162:    * @ignore
1163:    */
1164:   public static function get_date_format() {
1165:     if( empty( self::$_date_format ) ) self::$_date_format = get_option( 'date_format' );
1166:     
1167:     return self::$_date_format;
1168:   }
1169:   
1170:   /**
1171:    * get "clean" home_url.
1172:    *
1173:    * The plugin translate home url in according to current language.
1174:    * So if you call the wp function "home_url" it will home url with language information,
1175:    * in according to url modification mode.
1176:    *
1177:    * This function will return "real" home without any language information.
1178:    *
1179:    * @example
1180:    *
1181:    * home_url()<br />
1182:    *  www.example.com/it<br />
1183:    * <br />
1184:    * CMLUtils::home_url()<br />
1185:    *  www.example.com<br />
1186:    * 
1187:    * @return string
1188:    */
1189:   public static function home_url() {
1190:     if( empty( self::$_home_url ) ) {
1191:       $GLOBALS[ '_cml_no_translate_home_url' ] = true;
1192:       self::$_home_url = home_url();
1193: 
1194:       unset( $GLOBALS[ '_cml_no_translate_home_url' ] );
1195:     }
1196: 
1197:     return self::$_home_url;
1198:   }
1199:   
1200:   /**
1201:    * remove language information from url
1202:    * 
1203:    * @ignore
1204:    */
1205:   public static function clear_url( $url = null ) {
1206:     global $wp_rewrite;
1207: 
1208:     if( self::get_url_mode() != PRE_PATH 
1209:         || ( self::$_clean_applied == true &&
1210:         null === $url ) ) {
1211:       return self::$_language_detected;
1212:     }
1213: 
1214:     if( empty( self::$_url ) ) {
1215:       self::$_url = "http://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
1216:       self::$_request_url = str_replace( trailingslashit( self::home_url() ),
1217:                                         "", self::$_url );
1218:     }
1219: 
1220:     if( null === $url ) {
1221:       $_url = self::$_url;
1222:       $request_url = self::$_request_url;
1223:       
1224:       /*
1225:        * remove all parameters in url
1226:        */
1227:       self::$_clean_url = preg_replace( "/\?.*/", "", $_url );
1228:       self::$_clean_request = $request_url;
1229:     } else {
1230:       $_url = $url;
1231:       $request_url = str_replace( trailingslashit( self::home_url() ),
1232:                                         "", $url );
1233:     }
1234: 
1235:     $_url = $request_url;
1236:     $base_url = str_replace( "http://" . $_SERVER['HTTP_HOST'], "", get_option( 'home' ) );
1237: 
1238:     if( preg_match( "#^([a-z]{2})(/.*)?$#i", $_url, $match ) ) {
1239:       $lang = CMLLanguage::get_id_by_slug( $match[1] );
1240:       if( empty( $lang ) ) {
1241:         return $url;
1242:       }
1243: 
1244:       $_url = substr( $_url, 3 );
1245:       $_url = preg_replace( "/\?.*/", "", $_url );
1246: 
1247:       if( null === $url ) {
1248:         self::$_language_detected = $lang;
1249: 
1250:         CMLLanguage::set_current( self::$_language_detected );
1251: 
1252:         self::$_clean_url = trailingslashit( self::$_home_url ) . $_url;
1253:         self::$_clean_request = trailingslashit( $base_url ) . $_url;
1254:       } else {
1255:         $_url = trailingslashit( CMLUtils::home_url() ) . $_url;
1256:       }
1257:     }
1258:     
1259:     if( null === $url ) {
1260:       self::$_clean_applied = true;
1261:     }
1262: 
1263:     return ( null === $url ) ? self::$_language_detected : $_url;
1264:   }
1265: 
1266:   /**
1267:    * return current url withouth any language information.
1268:    *
1269:    * @example
1270:    * 
1271:    *  www.example.com/en/example<br />
1272:    *<br />
1273:    *  CMLUtils::get_clean_url() will return:<br />
1274:    *<br />
1275:    *    www.example.com/example
1276:    *
1277:    * @return string
1278:    */
1279:   public static function get_clean_url() {
1280:     return self::$_clean_url;
1281:   }
1282:   
1283:   /**
1284:    * get $_SERVER[ 'REQUEST_URI' ] with no language information.
1285:    *
1286:    * @return string
1287:    */
1288:   public static function get_clean_request() {
1289:     return self::$_clean_request;
1290:   }
1291:   
1292:   /**
1293:    * @ignore
1294:    */
1295:   public static function _set( $key, $value ) {
1296:     self::$_vars[ $key ] = $value;
1297:   }
1298:   
1299:   /**
1300:    * @ignore
1301:    */
1302:   public static function _get( $key ) {
1303:     return isset( self::$_vars[ $key ] ) ? self::$_vars[ $key ] : null;
1304:   }
1305:   
1306:   /**
1307:    * @ignore
1308:    */
1309:   public static function _append( $key, $value ) {
1310:     if( ! isset( self::$_vars[ $key ] ) ) {
1311:       self::$_vars[ $key ] = array();
1312:     }
1313:     
1314:     self::$_vars[ $key ][] = $value;
1315:   }
1316: }
1317: ?>
API documentation generated by ApiGen 2.8.0